"""Database connection module."""

import os
import logging
from typing import Optional

import motor.motor_asyncio
from pymongo.errors import ConnectionFailure, ServerSelectionTimeoutError
import redis.asyncio as redis

logger = logging.getLogger(__name__)

# MongoDB configuration
MONGODB_URL = os.getenv("MONGODB_URL", "mongodb://localhost:27017")
MONGODB_DATABASE = os.getenv("MONGODB_DATABASE", "ai_writing")

# Redis configuration
REDIS_URL = os.getenv("REDIS_URL", "redis://localhost:6379")

# Global instances
_mongodb_client: Optional[motor.motor_asyncio.AsyncIOMotorClient] = None
_redis_client: Optional[redis.Redis] = None


async def get_mongodb_client() -> motor.motor_asyncio.AsyncIOMotorClient:
    """Get MongoDB client instance.
    
    Returns:
        MongoDB client instance
    """
    global _mongodb_client
    
    if _mongodb_client is None:
        try:
            _mongodb_client = motor.motor_asyncio.AsyncIOMotorClient(
                MONGODB_URL,
                serverSelectionTimeoutMS=5000,
                connectTimeoutMS=10000,
                socketTimeoutMS=10000,
                maxPoolSize=50,
                minPoolSize=10
            )
            
            # Test connection
            await _mongodb_client.admin.command('ping')
            logger.info("MongoDB connection established")
            
        except (ConnectionFailure, ServerSelectionTimeoutError) as e:
            logger.error(f"Failed to connect to MongoDB: {e}")
            raise
    
    return _mongodb_client


async def get_redis_client() -> Optional[redis.Redis]:
    """Get Redis client instance.
    
    Returns:
        Redis client instance or None if connection fails
    """
    global _redis_client
    
    if _redis_client is None:
        try:
            _redis_client = redis.from_url(
                REDIS_URL,
                encoding="utf-8",
                decode_responses=True,
                max_connections=50
            )
            
            # Test connection
            await _redis_client.ping()
            logger.info("Redis connection established")
            
        except Exception as e:
            logger.warning(f"Redis connection failed (will use fallback): {e}")
            _redis_client = None
    
    return _redis_client


async def close_database_connections():
    """Close all database connections."""
    global _mongodb_client, _redis_client
    
    if _mongodb_client:
        _mongodb_client.close()
        _mongodb_client = None
        logger.info("MongoDB connection closed")
    
    if _redis_client:
        await _redis_client.close()
        _redis_client = None
        logger.info("Redis connection closed")


async def init_database():
    """Initialize database connections and create indexes."""
    # Get MongoDB client
    client = await get_mongodb_client()
    db = client[MONGODB_DATABASE]
    
    # Create indexes for conversations collection
    conversations = db.conversations
    
    try:
        # User index
        await conversations.create_index("user_id")
        
        # Timestamp indexes
        await conversations.create_index("created_at")
        await conversations.create_index("updated_at")
        
        # Search indexes
        await conversations.create_index("tags")
        await conversations.create_index("status")
        await conversations.create_index("category")
        
        # Sharing index (unique)
        await conversations.create_index(
            "sharing.share_id",
            unique=True,
            sparse=True
        )
        
        # Full-text search index
        await conversations.create_index(
            [("title", "text"), ("messages.content", "text")],
            name="conversation_text_search"
        )
        
        # Compound indexes for common queries
        await conversations.create_index(
            [("user_id", 1), ("status", 1), ("updated_at", -1)]
        )
        
        logger.info("MongoDB indexes created successfully")
        
    except Exception as e:
        logger.error(f"Failed to create indexes: {e}")
        raise
    
    # Try to initialize Redis
    await get_redis_client()


class DatabaseSession:
    """Context manager for database operations."""
    
    def __init__(self):
        self.mongodb_client = None
        self.redis_client = None
        self.db = None
    
    async def __aenter__(self):
        """Enter the context manager."""
        self.mongodb_client = await get_mongodb_client()
        self.redis_client = await get_redis_client()
        self.db = self.mongodb_client[MONGODB_DATABASE]
        return self
    
    async def __aexit__(self, exc_type, exc_val, exc_tb):
        """Exit the context manager."""
        # Connection pooling is handled by the clients
        pass
    
    @property
    def conversations(self):
        """Get conversations collection."""
        return self.db.conversations
    
    @property
    def api_keys(self):
        """Get API keys collection."""
        return self.db.api_keys


# Health check functions

async def check_mongodb_health() -> dict:
    """Check MongoDB health.
    
    Returns:
        Health status dictionary
    """
    try:
        client = await get_mongodb_client()
        result = await client.admin.command('ping')
        
        return {
            "status": "healthy",
            "response_time_ms": result.get('ok', 0)
        }
    except Exception as e:
        return {
            "status": "unhealthy",
            "error": str(e)
        }


async def check_redis_health() -> dict:
    """Check Redis health.
    
    Returns:
        Health status dictionary
    """
    try:
        client = await get_redis_client()
        if client:
            await client.ping()
            return {"status": "healthy"}
        else:
            return {
                "status": "unavailable",
                "message": "Redis not configured or unreachable"
            }
    except Exception as e:
        return {
            "status": "unhealthy",
            "error": str(e)
        }